#include "audioplay.h"
#include <QDebug>
#include <QList>

static QMutex m_mutex;

AudioPlay::AudioPlay(QObject *parent)
    : QObject(parent)
{
    m_nSampleRate = 8000;
    m_bAudioOpen = false;
    m_pAudioOutput = nullptr;
    m_pAudioThread = nullptr;
    setFormat();
    m_pThread = new QThread;
    m_pThread->start();
    connect(this,
            &AudioPlay::inputVoiceSignal,
            this,
            [&](QByteArray qbaData) {
        if (!m_bAudioOpen) {
            audioPlay();
        }
        emit sendDataSignal(qbaData);
    },
    Qt::QueuedConnection);

    connect(this,
            &AudioPlay::setSampleRateSignal,
            this,
            [&](int nSampleRate) {
        if (m_nSampleRate != nSampleRate) {
            m_nSampleRate = nSampleRate;
            setFormat();
        }
    },
    Qt::QueuedConnection);

    connect(this, &AudioPlay::stopAudio, this, [&] {
        m_bAudioOpen = false;
        releaseAudio();
    });
}

AudioPlay::~AudioPlay()
{
    releaseAudio();
    m_pThread->exit();
    if (m_pThread != nullptr) {
        m_pThread->deleteLater();
        m_pThread = nullptr;
    }
}

void AudioPlay::inputVoice(char *pcVoice, int nLen)
{
    emit inputVoiceSignal(QByteArray(pcVoice, nLen));
}

void AudioPlay::setSampleRate(int nSampleRate)
{
    emit setSampleRateSignal(nSampleRate);
}

void AudioPlay::stop()
{
    emit stopAudio();
}

void AudioPlay::audioStateChanged(QAudio::State state)
{
    switch (state) {
    case QAudio::IdleState:
        m_bAudioOpen = false;
        releaseAudio();
        setFormat();
        break;
    default:
        break;
    }
}

void AudioPlay::audioPlay()
{

    QList<QAudioDeviceInfo> outputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
    if (outputDevices.size() <= 0) {
        return;
    }
    if (m_pAudioOutput == nullptr) {
        m_pAudioOutput = new QAudioOutput(m_audioFormat);
        connect(m_pAudioOutput, &QAudioOutput::stateChanged, this, &AudioPlay::audioStateChanged);
        if (m_pAudioThread) {
            m_pAudioThread->deleteLater();
            m_pAudioThread = nullptr;
        }

        m_pAudioThread = new AudioThread(m_pAudioOutput);
        m_pAudioThread->moveToThread(m_pThread);

        connect(this,
                &AudioPlay::sendDataSignal,
                m_pAudioThread,
                &AudioThread::inputData,
                Qt::QueuedConnection);
    }
    m_bAudioOpen = true;
}

void AudioPlay::setFormat()
{
    if (m_pAudioOutput != nullptr) {
        m_pAudioOutput->reset();
        m_pAudioOutput->start();
    }
    //设置采样率
    m_audioFormat.setSampleRate(m_nSampleRate);
    //设置通道数
    m_audioFormat.setChannelCount(1);
    //设置采样大小，一般为8位或16位
    m_audioFormat.setSampleSize(16);
    //设置编码方式
    m_audioFormat.setCodec("audio/pcm");
    //设置字节序
    m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
    //设置样本数据类型
    m_audioFormat.setSampleType(QAudioFormat::SignedInt);
}

void AudioPlay::releaseAudio()
{
    if (m_pAudioThread != nullptr) {
        m_pAudioThread->deleteLater();
        m_pAudioThread = nullptr;
    }
    if (m_pAudioOutput != nullptr) {
        m_pAudioOutput->stop();
        m_pAudioOutput->deleteLater();
        m_pAudioOutput = nullptr;
    }
}

AudioDevice::AudioDevice(QObject *parent)
    : QIODevice(parent)
{
    QMutexLocker locker(&m_mutex);
    m_qbaAudioBuffer.clear();
}

void AudioDevice::inputData(char *pcData, int nLen)
{
    QMutexLocker locker(&m_mutex);
    m_qbaAudioBuffer.append(pcData, nLen);
}

void AudioDevice::start()
{
    if (!this->isOpen()) {
        open(QIODevice::ReadOnly);
    }
}

void AudioDevice::stop()
{
    QMutexLocker locker(&m_mutex);
    m_qbaAudioBuffer.clear();
    this->close();
}

qint64 AudioDevice::bytesAvailable() const
{
    QMutexLocker locker(&m_mutex);
    qint64 llReturn = m_qbaAudioBuffer.size() + QIODevice::bytesAvailable();
    return llReturn;
}

qint64 AudioDevice::readData(char *data, qint64 maxlen)
{
    QMutexLocker locker(&m_mutex);
    memset(data, 0, maxlen);
    if (m_qbaAudioBuffer.size() < maxlen) {
        maxlen = m_qbaAudioBuffer.size();
    }
    if (maxlen > 0) {
        memcpy(data, m_qbaAudioBuffer.left(maxlen).data(), maxlen);
        m_qbaAudioBuffer.remove(0, maxlen);
    }

    return maxlen;
}

qint64 AudioDevice::writeData(const char *data, qint64 len)
{
    Q_UNUSED(data);
    Q_UNUSED(len);
    return 0;
}

AudioThread::AudioThread(QAudioOutput *pAudioOutput, QObject *parent)
    : QObject(parent)
{
    m_pAudioOutput = nullptr;
    m_pAudioDevice = nullptr;

    m_pAudioDevice = new AudioDevice(this);
    m_pAudioDevice->start();
    m_pAudioOutput = pAudioOutput;
    m_pAudioOutput->start(m_pAudioDevice);
}

AudioThread::~AudioThread()
{
    if (m_pAudioDevice != nullptr) {
        m_pAudioDevice->stop();
        m_pAudioDevice->deleteLater();
        m_pAudioDevice = nullptr;
    }
}

void AudioThread::inputData(QByteArray qbaData)
{
    if (m_pAudioDevice != nullptr) {
        m_pAudioDevice->inputData(qbaData.data(), qbaData.size());
    }
}
